const jwt = require('jsonwebtoken');
const jwtConfig = require('../config/jwt');
const RefreshToken = require('../models/refreshToken');

/**
 * 生成访问令牌
 * @param {Object} payload - JWT负载数据
 * @returns {string} - 访问令牌
 */
const generateAccessToken = (payload) => {
  return jwt.sign(payload, jwtConfig.secret, { expiresIn: jwtConfig.accessTokenExpiresIn });
};

/**
 * 生成刷新令牌
 * @param {ObjectId} userId - 用户ID
 * @returns {Promise<Object>} - 刷新令牌对象
 */
const generateRefreshToken = async (userId) => {
  const expires = new Date();
  expires.setSeconds(expires.getSeconds() + jwtConfig.refreshTokenExpiresIn);
  
  const token = jwt.sign({ userId }, jwtConfig.secret, { expiresIn: jwtConfig.refreshTokenExpiresIn });
  
  const refreshToken = new RefreshToken({
    userId,
    token,
    expires
  });
  
  await refreshToken.save();
  return refreshToken;
};

/**
 * 验证访问令牌
 * @param {string} token - 访问令牌
 * @returns {Object|null} - 解析后的令牌数据或null
 */
const verifyAccessToken = (token) => {
  try {
    return jwt.verify(token, jwtConfig.secret);
  } catch (error) {
    return null;
  }
};

/**
 * 验证刷新令牌
 * @param {string} token - 刷新令牌
 * @returns {Promise<Object|null>} - 刷新令牌对象或null
 */
const verifyRefreshToken = async (token) => {
  try {
    const refreshToken = await RefreshToken.findOne({ token, revoked: false });
    
    if (!refreshToken || new Date() > refreshToken.expires) {
      return null;
    }
    
    return refreshToken;
  } catch (error) {
    return null;
  }
};

/**
 * 撤销刷新令牌
 * @param {string} token - 刷新令牌
 * @returns {Promise<boolean>} - 是否撤销成功
 */
const revokeRefreshToken = async (token) => {
  try {
    const result = await RefreshToken.findOneAndUpdate(
      { token, revoked: false },
      { revoked: true, revokedAt: new Date() },
      { new: true }
    );
    
    return !!result;
  } catch (error) {
    return false;
  }
};

/**
 * 撤销用户的所有刷新令牌
 * @param {ObjectId} userId - 用户ID
 * @returns {Promise<boolean>} - 是否撤销成功
 */
const revokeAllUserRefreshTokens = async (userId) => {
  try {
    await RefreshToken.updateMany(
      { userId, revoked: false },
      { revoked: true, revokedAt: new Date() }
    );
    return true;
  } catch (error) {
    return false;
  }
};

module.exports = {
  generateAccessToken,
  generateRefreshToken,
  verifyAccessToken,
  verifyRefreshToken,
  revokeRefreshToken,
  revokeAllUserRefreshTokens
};